import { useState, useCallback, useMemo } from 'react';
import { Table, Popconfirm, Form, Space, TableProps, Button } from 'antd';

import { SaveOutlined, CloseOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';

import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

import EditableCell from '@/biz-components/table-components/editable-cell';

import update from 'immutability-helper';
import { useIntl } from 'umi';

import { PlusOutlined } from '@ant-design/icons';
import { uuidv4 } from '@ey-utils/utils/utils';
import { DynamicObjectAny } from '@/typings';
import DragAbleRow from '@/biz-components/table-components/drag-able-row';

interface EditableTableProps<T = any> extends Omit<TableProps<any>, 'onChange'> {
  onChange: (value: any[]) => void;
  disabled?: boolean;
}

const EditableTable = ({ columns, onChange, dataSource, disabled }: EditableTableProps) => {
  const [form] = Form.useForm();

  const [editIndex, setEditIndex] = useState<number>(-1);

  const { formatMessage } = useIntl();

  const { validateFields } = form;

  const cancel = () => {
    setEditIndex(-1);
    form.resetFields();
  };

  const data = useMemo(() => {
    if (!dataSource?.length) {
      cancel();
    }

    return (
      dataSource
        ?.filter((val) => val)
        .map((item) => {
          const { tableId } = item || {};
          return {
            ...item,
            tableId: tableId || uuidv4(),
          };
        }) || []
    );
  }, [dataSource]);

  const triggerChange = (changedValue: any) => {
    onChange?.(changedValue);
  };

  const editableKey = useMemo(() => {
    // @ts-ignore
    return columns?.filter((item) => item.editable).map((item) => item.dataIndex) || [];
  }, [columns]);

  const isEditing = (rowIndex: number) => rowIndex === editIndex;

  const handleEdit = (record: any, rowIndex: number) => {
    form.resetFields();

    const formValues: DynamicObjectAny = {};

    editableKey.forEach((key) => {
      formValues[key] = record[key];
    });

    form.setFieldsValue(formValues);
    setEditIndex(rowIndex);
  };



  const handleDelete = (index: number) => {
    triggerChange(
      update(dataSource || [], {
        $splice: [[index, 1]],
      }),
    );
  };

  const handleSave = () => {
    validateFields().then((formValues) => {
      const record = dataSource?.[editIndex] || {};

      triggerChange(
        update(data, {
          $splice: [
            [
              editIndex,
              1,
              {
                ...record,
                ...formValues,
              },
            ],
          ],
        }),
      );

      cancel();
    });
  };

  const operationColumn = [
    {
      title: formatMessage({
        id: 'table.column.operation',
      }),
      dataIndex: 'operation',
      width: 120,
      render: (_: any, record: any, rowIndex: number) => {
        if (disabled) return;

        const editable = isEditing(rowIndex);

        return editable ? (
          <Space
            className="edit-table-btn-ctt"
            style={{
              border: 'none',
              margin: 0,
              padding: 0,
            }}
            size={[0, 0]}
          >
            <Button type="link" onClick={handleSave}>
              <SaveOutlined />
            </Button>

            <Popconfirm
              title={formatMessage({
                id: 'table.column.operation.btn.cancel.confirmTitle',
              })}
              onConfirm={cancel}
            >
              <Button type="link">
                <CloseOutlined />
              </Button>
            </Popconfirm>
          </Space>
        ) : (
          <Space
            className="edit-table-btn-ctt"
            style={{
              border: 'none',
              margin: 0,
              padding: 0,
            }}
            size={[0, 0]}
          >
            <Button
              type="link"
              onClick={() => {
                handleEdit(record, rowIndex);
              }}
            >
              <EditOutlined />
            </Button>

            <Popconfirm
              title={formatMessage({
                id: 'table.column.operation.btn.delete.confirmTitle',
              })}
              onConfirm={() => {
                handleDelete(rowIndex);
              }}
            >
              <Button type="link">
                <DeleteOutlined />
              </Button>
            </Popconfirm>
          </Space>
        );
      },
    },
  ];

  // @ts-ignore
  const mergedColumns = operationColumn.concat(columns || []).map((col) => {
    const { editable, dataIndex, title, component } = col;

    if (!editable) {
      return col;
    }
    return {
      ...col,
      onCell: (record: any, rowIndex: number) => ({
        record,
        dataIndex,
        title,
        component,
        editing: isEditing(rowIndex),
      }),
    };
  });

  const moveRow = useCallback(
    (dragIndex, hoverIndex) => {
      const dragRow = data[dragIndex];

      triggerChange(
        update(data, {
          $splice: [
            [dragIndex, 1],
            [hoverIndex, 0, dragRow],
          ],
        }),
      );
    },
    [data],
  );

  const handleAddClick = () => {
    triggerChange(
      update(data, {
        $push: [{}],
      }),
    );

    setEditIndex(data.length);
  };

  const renderTitle = () => {
    return (
      <Space
        className="edit-table-btn-ctt"
        style={{
          border: 'none',
          margin: 0,
        }}
      >
        <Button className="edit-table-add-btn" onClick={handleAddClick} disabled={disabled}>
          <PlusOutlined />
          {formatMessage({
            id: 'table.btn.add',
          })}
        </Button>
      </Space>
    );
  };

  const components = {
    body: {
      cell: EditableCell,
      row: DragAbleRow,
    },
  };

  return (
    <Form form={form} component={false}>
      <DndProvider backend={HTML5Backend}>
        <Table<any>
          rowKey="tableId"
          title={renderTitle}
          components={components}
          bordered
          dataSource={data}
          columns={mergedColumns}
          className="innerTable"
          rowClassName="editable-row"
          pagination={false}
          onRow={(record, index) => ({
            index,
            moveRow,
            dragType: 'EditableDragAbleRow',
          })}
        />
      </DndProvider>
    </Form>
  );
};

export default EditableTable;
